<template>
  <span>{{ displayNumber }}</span>
</template>

<script setup lang="ts">
import { ref, watch, onMounted, computed, defineProps } from 'vue';

const props = defineProps({
  value: {
    type: Number,
    required: true
  },
  duration: {
    type: Number,
    default: 1000
  },
  decimals: {
    type: Number,
    default: 0
  },
  prefix: {
    type: String,
    default: ''
  },
  suffix: {
    type: String,
    default: ''
  },
  separator: {
    type: String,
    default: ','
  },
  animation: {
    type: String,
    default: 'linear',
    validator: (value: string) => ['linear', 'easeOut', 'easeIn'].includes(value)
  },
  autoplay: {
    type: Boolean,
    default: true
  }
});

const startValue = ref(0);
const endValue = ref(props.value);
const currentValue = ref(0);
const animationId = ref<number | null>(null);
const startTime = ref<number | null>(null);

// 格式化数字
const formatNumber = (num: number) => {
  const fixed = num.toFixed(props.decimals);
  const parts = fixed.toString().split('.');
  parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, props.separator);
  return `${props.prefix}${parts.join('.')}${props.suffix}`;
};

const displayNumber = computed(() => {
  return formatNumber(currentValue.value);
});

// 动画函数
const animate = (timestamp: number) => {
  if (!startTime.value) {
    startTime.value = timestamp;
  }

  const elapsed = timestamp - startTime.value;
  let progress = Math.min(elapsed / props.duration, 1);

  // 根据不同的动画曲线调整进度
  if (props.animation === 'easeOut') {
    progress = 1 - Math.pow(1 - progress, 3);
  } else if (props.animation === 'easeIn') {
    progress = Math.pow(progress, 3);
  }

  currentValue.value = startValue.value + (endValue.value - startValue.value) * progress;

  if (progress < 1) {
    // 继续动画
    animationId.value = requestAnimationFrame(animate);
  } else {
    // 确保最终值是精确的
    currentValue.value = endValue.value;
    animationId.value = null;
    startTime.value = null;
  }
};

// 启动动画
const startAnimation = () => {
  // 取消之前的动画（如果有）
  if (animationId.value !== null) {
    cancelAnimationFrame(animationId.value);
  }

  // 保存起始值和目标值
  startValue.value = currentValue.value;
  endValue.value = props.value;

  // 如果值相同，不需要动画
  if (startValue.value === endValue.value) {
    return;
  }

  // 重置开始时间
  startTime.value = null;
  
  // 启动动画
  animationId.value = requestAnimationFrame(animate);
};

// 监视值的变化
watch(() => props.value, () => {
  if (props.autoplay) {
    startAnimation();
  }
}, { immediate: false });

// 初始化
onMounted(() => {
  // 初始值设为目标值
  currentValue.value = props.autoplay ? 0 : props.value;
  
  if (props.autoplay) {
    // 启动初始动画
    startAnimation();
  }
});
</script>

<style scoped>
/* 您可以根据需要添加样式 */
span {
  display: inline-block;
  transition: color 0.3s ease, transform 0.3s ease;
}
</style> 